/**
 * 
 */
package wayic.utunes;

import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArraySet;

import org.apache.log4j.Logger;

import com4j.Holder;

import wayic.itunes.api.ClassFactory;
import wayic.itunes.api.IITTrack;
import wayic.itunes.api.ITPlayButtonState;
import wayic.itunes.api.IiTunes;
import wayic.utunes.events.IsATrackSource;
import wayic.utunes.events.TrackEvent;
import wayic.utunes.events.TrackListener;
import wayic.utunes.lyrics.LyricsSearcher;

/**
 * @author ashesh . nishant @ gmail . com
 * 
 */
public class Itunes implements IsATrackSource, TrackListener {

    private static Logger  LOGGER = Logger.getLogger(Itunes.class);

    private IiTunes        ituneApp;
    private Thread         playerThread;
    private TimerTask      tracker;
    private List<IITTrack> trackHistory;
    private static Itunes  THIS   = new Itunes();
    private boolean        playing;

    public boolean isPlaying() {
        return playing;
    }

    public void setPlaying(boolean playing) {
        this.playing = playing;
    }

    public boolean isPaused() {
        return paused;
    }

    public void setPaused(boolean paused) {
        this.paused = paused;
    }

    private boolean            paused;
    private Set<TrackListener> trackListeners = new CopyOnWriteArraySet<TrackListener>();

    private Itunes() {
        ituneApp = ClassFactory.createiTunesApp();
        trackHistory = new Vector<IITTrack>();
        playerThread = new Thread(new Runnable() {
            public void run() {
                playPause();
            }
        });
        trackListeners.add(this);
        startTracker();

        LOGGER.debug("Starting UTunes...");
    }

    public void startTracker() {
        final Timer timer = new Timer();
        setPaused(false);
        setPlaying(true);
        tracker = new TimerTask() {
            public void run() {
                try {
                    IITTrack currentTrack = ituneApp.currentTrack();
                    Holder<Boolean> prevButtonEnabled = new Holder<Boolean>();
                    Holder<Boolean> nextButtonEnabled = new Holder<Boolean>();
                    Holder<ITPlayButtonState> playButtonstate = new Holder<ITPlayButtonState>();
                    ituneApp.getPlayerButtonsState(prevButtonEnabled, playButtonstate, nextButtonEnabled);
                    if (playButtonstate.value == ITPlayButtonState.ITPlayButtonStatePauseEnabled) {
                        setPaused(false);
                        if (!isPlaying()) {
                            fireTrackResumeEvent();
                        }
                        setPlaying(true);
                    } else if (playButtonstate.value == ITPlayButtonState.ITPlayButtonStatePlayEnabled) {
                        setPlaying(false);
                        if (!isPaused()) {
                            fireTrackPausedEvent();
                        }
                        setPaused(true);
                    }
                    if (areTracksSame(lastTrack(), currentTrack)) {
                        return;
                    }
                    fireTrackStoppedEvent();
                    if (trackHistory.contains(currentTrack)) {
                        trackHistory.remove(currentTrack);
                    }
                    if(isPlaying()){
                        trackHistory.add(currentTrack);
                    }
                    fireTrackStartedEvent();

                } catch (Exception ex) {
//                    ex.printStackTrace();
                    timer.cancel();
                    LOGGER.error(ex.getMessage());
                    LOGGER.error("UTunes SHUT DOWN.");
                    System.exit(-1);
                }
            }
        };
        LOGGER.debug("Starting iTunes Tracker...");
        timer.scheduleAtFixedRate(tracker, 1000, 3000);
    }

    public IITTrack lastTrack() {
        if (trackHistory.size() > 0) {
            return trackHistory.get(trackHistory.size() - 1);
        }
        return null;
    }

    public void dumpTrackInfo(IITTrack track) {
        if (track != null) {
            LOGGER.debug("            ........             ");
            LOGGER.debug("track           :   " + track.name());
            LOGGER.debug("album           :   " + track.album());
            LOGGER.debug("artist          :   " + track.artist());
            LOGGER.debug("been played     :   " + track.playedCount() + " times");
            LOGGER.debug("length          :   " + track.duration() + " seconds");
            LOGGER.debug("            ........             ");
        }
    }

    public static Itunes app() {
        return THIS;
    }

    protected void playPause() {
        try {
            ituneApp.playPause();
        } catch (Exception e) {
            LOGGER.debug(e.getMessage());
        }
    }

    public void play() {
        playerThread.start();
    }

    public IITTrack currentTrack() {
        try {
            return ituneApp.currentTrack();
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.debug(e.getMessage());
        }
        return null;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((ituneApp == null) ? 0 : ituneApp.hashCode());
        return result;
    }

    protected boolean areTracksSame(IITTrack track1, IITTrack track2) {
        if (track2 == null || track1 == null)
            return false;
        if (track1 == track2)
            return true;
        if (track1.name() == null) {
            if (track2.name() != null) {
                return false;
            }
        } else if (!track1.name().equals(track2.name())) {
            return false;
        }

        if (track1.artist() == null) {
            if (track2.artist() != null)
                return false;
        } else if (!track1.artist().equals(track2.artist()))
            return false;

        if (track1.album() == null) {
            if (track2.album() != null) {
                return false;
            }
        } else if (!track1.album().equals(track2.album())) {
            return false;
        }
        return true;
    }

    @Override
    public void fireTrackPausedEvent() {
        // playing track should have been added to the history by now
        IITTrack currentTrack = currentTrack();
        if (currentTrack == null) {
            return;
        }
        for (TrackListener trackListener : trackListeners) {
            trackListener.paused(new TrackEvent(currentTrack));
        }
    }

    @Override
    public void fireTrackResumeEvent() {
        // playing track should have been added to the history by now
        IITTrack currentTrack = currentTrack();
        if (currentTrack == null) {
            return;
        }
        for (TrackListener trackListener : trackListeners) {
            trackListener.resumed(new TrackEvent(currentTrack));
        }
    }

    @Override
    public void fireTrackStartedEvent() {
        // playing track should have been added to the history by now
        IITTrack currentTrack = currentTrack();
        if (currentTrack == null || isPaused()) {
            return;
        }
        for (TrackListener trackListener : trackListeners) {
            trackListener.started(new TrackEvent(currentTrack));
        }
    }

    @Override
    public void fireTrackStoppedEvent() {
        // track should NOT have been added to the history yet
        IITTrack lastTrack = lastTrack();
        if (lastTrack == null) {
            return;
        }
        for (TrackListener trackListener : trackListeners) {
            trackListener.stopped(new TrackEvent(lastTrack));
        }
    }

    @Override
    public void addTrackListener(TrackListener trackListener) {
        trackListeners.add(trackListener);
    }

    @Override
    public Set<TrackListener> getTrackListeners() {
        return trackListeners;
    }

    @Override
    public void removeTrackListener(TrackListener trackListener) {
        trackListeners.remove(trackListener);
    }

    @Override
    public void paused(TrackEvent tEvent) {
        LOGGER.debug("TRACK PAUSED : " + tEvent.getTrack().name());

    }

    @Override
    public void resumed(TrackEvent tEvent) {
        LOGGER.debug("TRACK RESUMED : " + tEvent.getTrack().name());
    }

    @Override
    public void started(TrackEvent event) {
        LOGGER.debug("TRACK STARTED");
        dumpTrackInfo(event.getTrack());
    }

    @Override
    public void stopped(TrackEvent event) {
        LOGGER.debug("Track STOPPED");

    }

    public static void main(String args[]) {
        // Itunes.app().play();
        LOGGER.debug("Playing Utunes...");
        Itunes utunes = Itunes.app();
        utunes.addTrackListener(new LyricsSearcher());
    }

}
